using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Collections;

namespace [%NAMESPACE%]
{
    public class MultiChoice : ContainerBase, IEnumerable<Choice>
    {
        #region Constructor
        public MultiChoice(ItemBase p_parentItem, string p_fieldName, bool p_fillInChoice, string[] p_choices, bool p_emptyAllowed)
            : base(p_parentItem, p_fieldName, p_emptyAllowed)
        {
            if (p_parentItem == null) throw new PointBridgeEx("MultiChoice constructor: p_parentItem is null.");
            if (p_fieldName == null) throw new PointBridgeEx("MultiChoice constructor: p_fieldName is null.");

            fillInChoice = p_fillInChoice;

            choices = p_choices;
        }
        #endregion

        #region Methods
        public Choice this[int key]
        {
            get { return _arr[key]; }
        }
        public int Count
        {
            get { return _arr.Count; }
        }
        public override void SetEmpty()
        {
            _arr.Clear();
            ForceUpdate();
        }

        public void AddSelection(int newSelectedChoicesIndex)
        {
            if (newSelectedChoicesIndex < 0 || newSelectedChoicesIndex >= choices.Length) throw new PointBridgeEx("Choice.ChangeSelection(): newSelectedChoicesIndex (" + newSelectedChoicesIndex + ") is outside of bounds of choices array.");
            AddSelection(choices[newSelectedChoicesIndex]);
        }
        public void AddSelection(string newValueString)
        {
            if (ValidateChoiceString(newValueString) == false) throw new PointBridgeEx("MultiChoice.AddSelection(): '" + newValueString + "' is not a valid selection. Consider using Choice.AddCustomStringSelection() method if this is intended.");
            AddSelectionNoValidation(newValueString);
        }
        public void AddCustomStringSelection(string newValueString)
        {
            //validate that custom values are allowed
            SPFieldMultiChoice choiceColumnDef = (SPFieldMultiChoice)parentItem.item.ParentList.Fields[fieldName];
            if (choiceColumnDef.FillInChoice != true) throw new PointBridgeEx("MultiChoice.AddCustomStringSelection(): Custom values are not allowed for field '" + fieldName + "'");

            //validate that this is a custom value
            if (ValidateChoiceString(newValueString) == true) throw new PointBridgeEx("MultiChoice.AddCustomStringSelection(): '" + newValueString + "' is not a custom selection. Consider using MultiChoice.AddSelection() method if this is intended.");

            AddSelectionNoValidation(newValueString);
        }
        public void RemoveSelection(string valueStringToRemove)
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                if (_arr[i].valueString == valueStringToRemove)
                {
                    _arr.RemoveAt(i);
                    ForceUpdate();
                    return;
                }
            }
            throw new PointBridgeEx("Choice.RemoveLookupSelection(): unable to find valueStringToRemove = " + valueStringToRemove);
        }
        public Choice FindSelection(string valueString)
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                if (_arr[i].valueString == valueString) return _arr[i];
            }
            return null;
        }
        public bool ContainsSelection(string valueString)
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                if (_arr[i].valueString == valueString) return true;
            }
            return false;
        }
        public bool ValidateChoiceString(string str)
        {
            return Choice.ValidateChoiceString(str, choices);
        }
        public string GetSemicolonSeparatedString()
        {
            StringBuilder str = new StringBuilder();
            bool first = true;
            foreach (Choice option in this)
            {
                if (first == true) first = false;
                else str.Append("; ");
                str.Append(option.valueString);
            }
            return str.ToString();
        }
        public override string ToString()
        {
            if (isEmpty == true) return "<Empty>";
            else return GetSemicolonSeparatedString();
        }

        public override void ForceUpdate()
        {
            parentItem.item[fieldName] = ToSPRepresentation();
        }
        //Format: ";#Enter Choice #1;#Enter Choice 2;#"
        public override object ToSPRepresentation()
        {
            if (_arr.Count == 0)
            {
                if (emptyAllowed == true) return null;
                else throw new PointBridgeEx("MultiChoice.ToSPRepresentation(): count is 0 while emptyAllowed is false");
            }
            Dictionary<string, bool> valueStrings = new Dictionary<string, bool>();
            StringBuilder output = new StringBuilder();
            output.Append(";#");
            bool customChoiceAlreadyExists = false;
            foreach (Choice option in _arr)
            {
                if (option.valueString == null) throw new PointBridgeEx("MultiChoice.ToSPRepresentation(): id==null. This should never happen.");
                if (valueStrings.ContainsKey(option.valueString)) throw new PointBridgeEx("MultiChoice.ToSPRepresentation(): Multi-Choice contains a duplicate valueString = '" + option.valueString + "'");
                valueStrings.Add(option.valueString, true);
                if (ValidateChoiceString(option.valueString) == false)
                {
                    if (customChoiceAlreadyExists == true) throw new PointBridgeEx("MultiChoice.ToSPRepresentation():SharePoint multi-choice select may only contain one custom selection string");
                    customChoiceAlreadyExists = true;
                }
                output.Append(option.valueString + ";#");
            }
            return output.ToString();
        }
        public override void InitFromSPRepresentation(object obj)
        {
            _arr.Clear();
            if (obj == null)
            {
                if (emptyAllowed == true) return;
                else throw new PointBridgeEx("MultiChoice.InitFromSPRepresentation(): object is not initialized while emptyAllowed is false");
            }

            string str = (string)obj;
            string[] separators = new string[1];
            separators[0] = ";#";
            string[] splits = str.Trim().Split(separators, StringSplitOptions.RemoveEmptyEntries);

            foreach (string split in splits) _arr.Add(new Choice(this, split, choices));
        }
        public static int GetCountFromSPRepresentation(object obj)
        {
            if (obj == null) return 0;
            string str = (string)obj;
            string[] separators = new string[1];
            separators[0] = ";#";
            string[] splits = str.Trim().Split(separators, StringSplitOptions.RemoveEmptyEntries);
            return splits.Length;
        }
        #endregion

        #region Public Properties
        public SPSite site
        {
            get
            {
                return web.Site;
            }
        }
        public SPWeb web
        {
            get
            {
                return parentItem.item.Web;
            }
        }
        public override bool isEmpty
        {
            get
            {
                if (_arr.Count == 0) return true;
                else return false;
            }
        }

        public readonly bool fillInChoice;

        public readonly string[] choices;
        #endregion

        #region IEnumerable implementation
        public IEnumerator<Choice> GetEnumerator()
        {
            for (int i = 0; i < _arr.Count; i++)
            {
                yield return _arr[i];
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Private Helper Methods
        public void AddSelectionNoValidation(string newValueString)
        {
            //check if alredy selected
            foreach (Choice option in _arr)
            {
                if (option.valueString == newValueString) return;
            }

            Choice item = new Choice(this, newValueString, choices);
            _arr.Add(item);
            ForceUpdate();
        }
        #endregion

        #region Internal fields
        protected List<Choice> _arr = new List<Choice>();
        #endregion
    }
}